use super::{
    json, ok, Base, Client, Collect, KeyNode, Level, Lock, Resp, SStr, SvCache, VBase, VMap, Value,
};

pub struct Stock;

impl Base for Stock {}

impl Stock {
    pub async fn do_cmd(
        &self,
        model: &str,
        para: &Value,
        cmd: &str,
        client: &Client,
        cache: SvCache,
        lock: Lock,
    ) -> Resp {
        let data = para.ckobj()?;
        let line = data.ck_str("line")?;

        let collect = Collect::new(client, cache, line);

        match cmd {
            "rm" => {
                let _ = lock.lock().await;

                let sn = data.ck_str("k")?;
                let k_all = collect.key_all(model)?;
                let mut put = Vec::new();
                let mut del = Vec::new();

                let help = Level::new(model, &collect);

                help.rm_year_item(&sn, &mut put, &mut del).await?;

                collect.del_mass_item(&k_all, sn, &mut put, &mut del);

                collect.commit(Some(&put), Some(&del)).await?;

                ok!()
            }
            "rmset" => {
                let _ = lock.lock().await;

                let val = data.ck_array("v")?;
                let k_all = collect.key_all(model)?;
                let mut set = SStr::new();
                let mut put = Vec::new();
                let mut del = Vec::new();

                for sn in val.iter() {
                    let sn = sn.ckstr()?;
                    set.insert(sn.to_string());
                }

                let help = Level::new(model, &collect);
                help.rm_year_set(&set, &mut put, &mut del).await?;

                collect.del_mass_set(&k_all, &set, false, &mut put, &mut del);

                collect.commit(Some(&put), Some(&del)).await?;

                ok!()
            }
            "list" => {
                let help = Level::new(model, &collect);
                let body = help.list_year().await?;
                ok!(body)
            }
            "add" => {
                let val = data.ck_obj("v")?;
                let sn = val.ck_str_empty_trim("sn")?;
                let k_sn = collect.key_sn(model, &sn)?;

                let _ = lock.lock().await;

                let y = base::cur_time("%Y");
                let pstart = base::cur_time("%Y-%m-%d %H:%M:%S");

                let mut tmp = val.clone();
                tmp.insert("pstart".to_string(), json!(pstart));

                let mut put = vec![(k_sn, json!(tmp))];

                let help = Level::new(model, &collect);
                help.add_sn_to_year(&y, &sn, &mut put)?;

                collect.commit(Some(&put), None).await?;

                ok!()
            }
            "madd" => {
                let _ = lock.lock().await;
                let v_data = data.ck_array("v")?;

                let y = base::cur_time("%Y");
                let pstart = base::cur_time("%Y-%m-%d %H:%M:%S");
                let help = Level::new(model, &collect);

                let mut put = Vec::new();
                let mut y_put = Vec::new();

                for val in v_data.iter() {
                    let val = val.ckobj()?;

                    let sn = val.ck_str_empty_trim("sn")?;
                    let k_sn = collect.key_sn(model, sn)?;

                    if let Ok(_) = collect.item(&k_sn).await {
                        collect.merge(&k_sn, &val, &mut put)?;
                    } else {
                        let mut tmp = val.clone();
                        tmp.insert("pstart".to_string(), json!(pstart));

                        put.push((k_sn, json!(tmp)));
                        y_put.push(json!(sn));
                    }
                }

                help.add_vec_to_year(&y, &y_put, &mut put)?;

                collect.commit(Some(&put), None).await?;

                ok!()
            }
            _ => collect.do_cmd(model, cmd, para, lock, None).await,
        }
    }
}
